package cn.qzuie.smart.module.dorm.service.assettype;

import cn.hutool.core.collection.CollUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import cn.qzuie.smart.module.dorm.controller.admin.assettype.vo.*;
import cn.qzuie.smart.module.dorm.dal.dataobject.assettype.AssetTypeDO;
import cn.qzuie.smart.framework.common.pojo.PageResult;
import cn.qzuie.smart.framework.common.pojo.PageParam;
import cn.qzuie.smart.framework.common.util.object.BeanUtils;

import cn.qzuie.smart.module.dorm.dal.mysql.assettype.AssetTypeMapper;

import static cn.qzuie.smart.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.qzuie.smart.framework.common.util.collection.CollectionUtils.convertList;
import static cn.qzuie.smart.framework.common.util.collection.CollectionUtils.diffList;
import static cn.qzuie.smart.module.dorm.enums.ErrorCodeConstants.*;

/**
 * 资产类型 Service 实现类
 *
 * @author 吴宗波
 */
@Service
@Validated
public class AssetTypeServiceImpl implements AssetTypeService {

    @Resource
    private AssetTypeMapper assetTypeMapper;

    @Override
    public Long createAssetType(AssetTypeSaveReqVO createReqVO) {
        // 校验父编号的有效性
        validateParentAssetType(null, createReqVO.getParentId());
        // 校验分类的唯一性
        validateAssetTypeNameUnique(null, createReqVO.getParentId(), createReqVO.getName());

        // 插入
        AssetTypeDO assetType = BeanUtils.toBean(createReqVO, AssetTypeDO.class);
        assetTypeMapper.insert(assetType);

        // 返回
        return assetType.getId();
    }

    @Override
    public void updateAssetType(AssetTypeSaveReqVO updateReqVO) {
        // 校验存在
        validateAssetTypeExists(updateReqVO.getId());
        // 校验父编号的有效性
        validateParentAssetType(updateReqVO.getId(), updateReqVO.getParentId());
        // 校验分类的唯一性
        validateAssetTypeNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());

        // 更新
        AssetTypeDO updateObj = BeanUtils.toBean(updateReqVO, AssetTypeDO.class);
        assetTypeMapper.updateById(updateObj);
    }

    @Override
    public void deleteAssetType(Long id) {
        // 校验存在
        validateAssetTypeExists(id);
        // 校验是否有子资产类型
        if (assetTypeMapper.selectCountByParentId(id) > 0) {
            throw exception(ASSET_TYPE_EXITS_CHILDREN);
        }
        // 删除
        assetTypeMapper.deleteById(id);
    }


    private void validateAssetTypeExists(Long id) {
        if (assetTypeMapper.selectById(id) == null) {
            throw exception(ASSET_TYPE_NOT_EXISTS);
        }
    }

    private void validateParentAssetType(Long id, Long parentId) {
        if (parentId == null || AssetTypeDO.PARENT_ID_ROOT.equals(parentId)) {
            return;
        }
        // 1. 不能设置自己为父资产类型
        if (Objects.equals(id, parentId)) {
            throw exception(ASSET_TYPE_PARENT_ERROR);
        }
        // 2. 父资产类型不存在
        AssetTypeDO parentAssetType = assetTypeMapper.selectById(parentId);
        if (parentAssetType == null) {
            throw exception(ASSET_TYPE_PARENT_NOT_EXITS);
        }
        // 3. 递归校验父资产类型，如果父资产类型是自己的子资产类型，则报错，避免形成环路
        if (id == null) { // id 为空，说明新增，不需要考虑环路
            return;
        }
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            // 3.1 校验环路
            parentId = parentAssetType.getParentId();
            if (Objects.equals(id, parentId)) {
                throw exception(ASSET_TYPE_PARENT_IS_CHILD);
            }
            // 3.2 继续递归下一级父资产类型
            if (parentId == null || AssetTypeDO.PARENT_ID_ROOT.equals(parentId)) {
                break;
            }
            parentAssetType = assetTypeMapper.selectById(parentId);
            if (parentAssetType == null) {
                break;
            }
        }
    }

    private void validateAssetTypeNameUnique(Long id, Long parentId, String name) {
        AssetTypeDO assetType = assetTypeMapper.selectByParentIdAndName(parentId, name);
        if (assetType == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的资产类型
        if (id == null) {
            throw exception(ASSET_TYPE_NAME_DUPLICATE);
        }
        if (!Objects.equals(assetType.getId(), id)) {
            throw exception(ASSET_TYPE_NAME_DUPLICATE);
        }
    }

    @Override
    public AssetTypeDO getAssetType(Long id) {
        return assetTypeMapper.selectById(id);
    }

    @Override
    public List<AssetTypeDO> getAssetTypeList(AssetTypeListReqVO listReqVO) {
        return assetTypeMapper.selectList(listReqVO);
    }

    @Override
    public List<AssetTypeDO> all() {
        return assetTypeMapper.selectList();
    }

}